﻿using System;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Security.Principal;

using Paragon.Logging;

namespace Paragon.Web
{
    public class LogModule : IHttpModule
    {
        private static readonly Logger log = LogProvider.GetLog(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public void Init(HttpApplication context)
        {
            context.Error += new EventHandler(OnError);
            context.BeginRequest += new EventHandler(OnRequestBegin);
            context.EndRequest += new EventHandler(OnRequestComplete);
            context.PostAuthenticateRequest += new EventHandler(OnPostAuthenticateRequest);

            IHttpModule sessionModule = context.Modules["Session"];
            if (sessionModule != null)
            {
                SessionStateModule sessionStateModule = (SessionStateModule)sessionModule;
                sessionStateModule.Start += new EventHandler(OnSessionStart);
            }
        }
        
        public void Dispose() { }

        #region HTTP Request Events

        public void OnError(object source, EventArgs e)
        {
            log.Critical("Http Request Error, Unhandled: ", HttpContext.Current.Error);
        }

        public void OnRequestBegin(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;

            // Sets various parameters for logging purposes
            ThreadContext.CurrentContext[Logger.IP_ADDRESS_KEY] = current.Request.ServerVariables["REMOTE_ADDR"];
            ThreadContext.CurrentContext[Logger.HTTP_METHOD] = current.Request.ServerVariables["REQUEST_METHOD"];
            ThreadContext.CurrentContext[Logger.URL_KEY] = current.Request.ServerVariables["SCRIPT_NAME"];
            ThreadContext.CurrentContext[Logger.REFERRER] = current.Request.ServerVariables["HTTP_REFERER"];
            ThreadContext.CurrentContext[Logger.USER_AGENT] = current.Request.ServerVariables["HTTP_USER_AGENT"];
            ThreadContext.CurrentContext[Logger.QUERY_STRING] = current.Request.ServerVariables["QUERY_STRING"];

            // Sets the session id for logging
            if (current.Session != null)
            {
                ThreadContext.CurrentContext[Logger.SESSION_ID_KEY] = current.Session.SessionID;
            }
            else
            {
                ThreadContext.CurrentContext[Logger.SESSION_ID_KEY] = "[unassigned]";
            }

            // Sets the authenticated user name
            if (current.User != null && current.User.Identity != null && current.User.Identity.Name != null)
            {
                ThreadContext.CurrentContext[Logger.USERNAME_KEY] = current.User.Identity.Name;
            }
            else
            {
                ThreadContext.CurrentContext[Logger.USERNAME_KEY] = "Unauthenticated";
            }

            //log.Information("Request: " + current.Request.RawUrl);
            HttpContext.Current.Items.Add("PerformanceStart", DateTime.Now);
        }

        public void OnRequestComplete(object sender, EventArgs e)
        {
            if (HttpContext.Current.Items["PerformanceStart"] != null)
            {
                DateTime start = (DateTime)HttpContext.Current.Items["PerformanceStart"];

                //log.Verbose(string.Format("Request({0}) Completed In: {1}ms", HttpContext.Current.Request.RawUrl, DateTime.Now.Subtract(start).TotalMilliseconds));
            }
        }

        public void OnPostAuthenticateRequest(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;

            // Sets the authenticated user name after the authenticate is complete
            if (current.User != null && current.User.Identity != null && current.User.Identity.Name != null)
            {
                ThreadContext.CurrentContext[Logger.USERNAME_KEY] = current.User.Identity.Name;
            }
            else
            {
                ThreadContext.CurrentContext[Logger.USERNAME_KEY] = "Unauthenticated";
            }
        }

        public void OnSessionStart(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;

            // Sets the session id for logging
            if (current.Session != null)
            {
                ThreadContext.CurrentContext[Logger.SESSION_ID_KEY] = current.Session.SessionID;
            }
            else
            {
                ThreadContext.CurrentContext[Logger.SESSION_ID_KEY] = "[unassigned]";
            }
        }

        #endregion
    }
}
